/**
 * \file   bootloader.h
 * \author fabianjsm
 * \date   Noviembre de 2011
 * 
 *  Este archivo es parte del proyecto MPHB, aplicación que se comunica
 * a traves del puerto USB con el bootloader en un microcontrolador PIC
 * de la familia 18, 24 o 32 para programarlo utilizando el protocolo
 * HID-Bootloader de Microchip.
 * 
 *  El codigo fuente esta diponible a traves del repositorio SVN de
 * Google:
 * 
 *      http://mphb.googlecode.com/svn/trunk
 * 
 * Fabian Jesus Machado (fabianjsm@gmail.com, twitter@fabianjsm).
 * Alumno de Ingenieria Electronica, Universidad Nacional De Misiones
 * (U.Na.M), Facultad de Ingeniería de Obera.
 * 
 */
#ifndef BOOTLOADER_H
#define BOOTLOADER_H

/* Identificacion del HID por VID-PID */
#define VENDOR_ID                       0x04D8
#define PRODUCT_ID                      0x003C

/* Para libusb_set_configuration */
#define HID_CONFIGURATION               0x01

#define ENDPOINT_INT_IN                 0x81
#define ENDPOINT_INT_OUT                0x01
#define TIMEOUT                         1000

// Valores de solicitudes de clases HID especificas.
// Ver seccion 7.2 de la especificacion HID.
#define HID_GET_REPORT                  0x01
#define HID_GET_IDLE                    0x02
#define HID_GET_PROTOCOL                0x03
#define HID_SET_REPORT                  0x09
#define HID_SET_IDLE                    0x0A
#define HID_SET_PROTOCOL                0x0B
#define HID_REPORT_TYPE_INPUT           0x01
#define HID_REPORT_TYPE_OUTPUT          0x02
#define HID_REPORT_TYPE_FEATURE         0x03

// Comandos para el bootloader
#define QUERY_DEVICE                    0x02
#define UNLOCK_CONFIG                   0x03
#define ERASE_DEVICE                    0x04
#define PROGRAM_DEVICE                  0x05
#define PROGRAM_COMPLETE                0x06
#define GET_DATA                        0x07
#define RESET_DEVICE                    0x08
#define GET_ENCRYPTED_FF                0xFF

// Resultados de una consulta (QUERY)
#define QUERY_IDLE                      0xFF
#define QUERY_RUNNING                   0x00
#define QUERY_SUCCESS                   0x01
#define QUERY_WRITE_FILE_FAILED         0x02
#define QUERY_READ_FILE_FAILED          0x03
#define QUERY_MALLOC_FAILED             0x04

// Resultados de una operacion de programacion (PROGRAMMING)
#define PROGRAM_IDLE                    0xFF
#define PROGRAM_RUNNING                 0x00
#define PROGRAM_SUCCESS                 0x01
#define PROGRAM_WRITE_FILE_FAILED       0x02
#define PROGRAM_READ_FILE_FAILED        0x03
#define PROGRAM_RUNNING_ERASE           0x05
#define PROGRAM_RUNNING_PROGRAM         0x06

// Resultados de una operacion de borrado (ERASE)
#define ERASE_IDLE                      0xFF
#define ERASE_RUNNING                   0x00
#define ERASE_SUCCESS                   0x01
#define ERASE_WRITE_FILE_FAILED         0x02
#define ERASE_READ_FILE_FAILED          0x03
#define ERASE_VERIFY_FAILURE            0x04
#define ERASE_POST_QUERY_FAILURE        0x05
#define ERASE_POST_QUERY_RUNNING        0x06
#define ERASE_POST_QUERY_SUCCESS        0x07

// Resultados de una operacion de verificacion (VERIFY)
#define VERIFY_IDLE                     0xFF
#define VERIFY_RUNNING                  0x00
#define VERIFY_SUCCESS                  0x01
#define VERIFY_WRITE_FILE_FAILED        0x02
#define VERIFY_READ_FILE_FAILED         0x03
#define VERIFY_MISMATCH_FAILURE         0x04

// Resultados de un operacion de lectura (READ)
#define READ_IDLE                       0xFF
#define READ_RUNNING                    0x00
#define READ_SUCCESS                    0x01
#define READ_READ_FILE_FAILED           0x02
#define READ_WRITE_FILE_FAILED          0x03

// Resultados de desbloqueo de configuracion (UNLOCK_CONFIG)
#define UNLOCK_CONFIG_IDLE              0xFF
#define UNLOCK_CONFIG_RUNNING           0x00
#define UNLOCK_CONFIG_SUCCESS           0x01
#define UNLOCK_CONFIG_FAILURE           0x02

// Estados del bootloader
#define BOOTLOADER_IDLE                 0xFF
#define BOOTLOADER_QUERY                0x00
#define BOOTLOADER_PROGRAM              0x01
#define BOOTLOADER_ERASE                0x02
#define BOOTLOADER_VERIFY               0x03
#define BOOTLOADER_READ                 0x04
#define BOOTLOADER_UNLOCK_CONFIG        0x05
#define BOOTLOADER_RESET                0x06

// Resultados de un reset (RESET)
#define RESET_IDLE                      0xFF
#define RESET_RUNNING                   0x00
#define RESET_SUCCESS                   0x01
#define RESET_WRITE_FILE_FAILED         0x02

// Tipos de regiones de memoria
#define MEMORY_REGION_PROGRAM_MEM       0x01
#define MEMORY_REGION_EEDATA            0x02
#define MEMORY_REGION_CONFIG            0x03
#define MEMORY_REGION_END               0xFF

// Tipos de linea HEX
#define HEX_FILE_EXTENDED_LINEAR_ADDRESS 0x04
#define HEX_FILE_EOF                     0x01
#define HEX_FILE_DATA                    0x00

// Numero de bytes por linea del archivo HEX
#define HEX_FILE_BYTES_PER_LINE          16

// Familias de dispositivos
#define DEVICE_FAMILY_PIC18              1
#define DEVICE_FAMILY_PIC24              2
#define DEVICE_FAMILY_PIC32              3

#define ERROR_SUCCESS                    1

#define PIC24_RESET_REMAP_OFFSET         0x1400
#define MAX_DATA_REGIONS                 6

#ifdef LINUX
#define    DETACH_USB true
#else
#define    DETACH_USB false
#endif /* LINUX */

typedef unsigned int DWORD;
typedef unsigned short WORD;

#pragma pack(1)
/**
 *  La estructura MEMORY_REGION contiene el tipo (programa, dato,
 * configuracion), la direccion y el tamaño de una region de memoria,
 * pero no alberga su buffer de datos.
 */
struct MEMORY_REGION {
    unsigned char Type;
    DWORD Address;
    DWORD Size;
};

/**
 * La structura BOOTLOADER_COMMAND encapsula los paquetes utilizados en
 * toda transaccion con el bootloader. */
union BOOTLOADER_COMMAND {
    struct {
        unsigned char Command;
        unsigned char Pad[63];
    } EnterBootloader;
    struct {
        unsigned char Command;
        unsigned char Pad[63];
    } QueryDevice;
    struct {
        unsigned char Command;
        unsigned char BytesPerPacket;
        unsigned char DeviceFamily;
        MEMORY_REGION MemoryRegions[MAX_DATA_REGIONS];
        unsigned char Pad[8];
    } QueryResults;
    struct {
        unsigned char Command;
        unsigned char Setting;
        unsigned char Pad[62];
    } UnlockConfig;
    struct {
        unsigned char Command;
        unsigned char Pad[63];
    } EraseDevice;
    struct {
        unsigned char Command;
        DWORD Address;
        unsigned char BytesPerPacket;
        unsigned char Data[58];
    } ProgramDevice;
    struct {
        unsigned char Command;
        unsigned char Pad[63];
    } ProgramComplete;
    struct {
        unsigned char Command;
        DWORD Address;
        unsigned char BytesPerPacket;
        unsigned char Pad[58];
    } GetData;
    struct {
        unsigned char Command;
        DWORD Address;
        unsigned char BytesPerPacket;
        unsigned char Data[58];
    } GetDataResults;
    struct {
        unsigned char Command;
        unsigned char Pad[63];
    } ResetDevice;
    struct {
        unsigned char Command;
        unsigned char blockSize;
        unsigned char Data[63];
    } GetEncryptedFFResults;
    struct {
        unsigned char Data[64];
    } PacketData;
    unsigned char RawData[65];
};
#pragma pack() // pack(0)

#endif /* BOOTLOADER_H */
